<?php
namespace Sdk\Order\Adapter\OrderLTL;

use Marmot\Core;
use Marmot\Interfaces\INull;
use Marmot\Interfaces\IRestfulTranslator;

use Sdk\Common\Model\Interfaces\IOperateAble;
use Sdk\Common\Adapter\CommonRestfulAdapter;

use Sdk\Common\Adapter\Traits\MapErrorsTrait;
use Sdk\Common\Adapter\Traits\FetchAbleRestfulAdapterTrait;
use Sdk\Common\Adapter\Traits\OperateAbleRestfulAdapterTrait;

use Sdk\Order\Model\OrderLTL;
use Sdk\Order\Model\NullOrderLTL;
use Sdk\Order\Translator\OrderLTLRestfulTranslator;

use Sdk\Order\Model\NullOrderPriceReport;
use Sdk\Order\Translator\OrderPriceReportRestfulTranslator;

use Sdk\Order\Model\ItemLTL;
use Sdk\Order\Translator\ItemLTLRestfulTranslator;

use Sdk\Application\ParseTask\Model\ParseTask;
use Sdk\Application\ParseTask\Model\NullParseTask;
use Sdk\Application\ParseTask\Translator\ParseTaskRestfulTranslator;

class OrderLTLRestfulAdapter extends CommonRestfulAdapter implements IOrderLTLAdapter
{
    use FetchAbleRestfulAdapterTrait,
        OperateAbleRestfulAdapterTrait,
        MapErrorsTrait;

    const MAP_ERROR = array(
        100001 => array(
            'remark' => REMARK_FORMAT_INCORRECT,//备注格式错误
            'items' => ITEMS_FORMAT_INCORRECT,//货物信息格式错误
            'weekendDelivery' => WEEKEND_DELIVERY_FORMAT_INCORRECT,//周末送货格式错误
            'deliveryName' => DELIVERYNAME_FORMAT_INCORRECT,//收货人格式错误
            'idfPickup' => IDF_PICKUP_FORMAT_INCORRECT,//idfPickup格式错误
            'bookingPickupDate' => BOOKINGPICKUPDATE_FORMAT_INCORRECT,//预订取货时间（日期）格式错误
            'pickupZipCode' => PICKUPZIPCODE_FORMAT_INCORRECT,//取货邮编格式错误
            'pickupAddressType' => PICKUPADDRESSTYPE_FORMAT_INCORRECT,//发货地址类型格式错误
            'deliveryZipCode' => DELIVERYZIPCODE_FORMAT_INCORRECT,//送货邮编格式错误
            'deliveryAddressType' => DELIVERYADDRESSTYPE_FORMAT_INCORRECT,//送货地址类型格式错误
            'pickupNeedTransport' => PICKUPNEEDTRANSPORT_FORMAT_INCORRECT,//取货需要室内搬运型格式不正确，请重新输入
            'pickupNeedLiftgate' => PICKUPNEEDLIFTGATE_FORMAT_INCORRECT,//取货需要卡车升降台格式不正确，请重新输入
            'poNumber' => PONUMBER_FORMAT_INCORRECT,//poNumber格式错误
            'pickupVehicleType' => PICKUPVEHICLETYPE_FORMAT_INCORRECT,//取货车辆类型格式错误
            'deliveryDescription' => DELIVERYDESCRIPTION_FORMAT_INCORRECT,//整体货物描述格式错误
            'pickupRequirement' => PICKUPREQUIREMENT_FORMAT_INCORRECT,//取货要求格式错误
            'deliveryRequirement' => DELIVERYREQUIREMENT_FORMAT_INCORRECT,//送货要求格式错误
            'readyTime' => READYTIME_FORMAT_INCORRECT,//取货最早时间（时分）格式错误
            'closeTime' => CLOSETIME_FORMAT_INCORRECT,//取货最晚时间（时分）格式错误
            'deliveryReadyTime' => DELIVERYREADYTIME_FORMAT_INCORRECT,//送达卸货最早时间（时分）格式错误
            'deliveryCloseTime' => DELIVERYCLOSETIME_FORMAT_INCORRECT,//送达卸货最晚时间（时分）格式错误
            'deliveryNeedTransport' => DELIVERYNEEDTRANSPORT_FORMAT_INCORRECT,//送货需要室内搬运型格式不正确，请重新输入
            'deliveryNeedLiftgate' => DELIVERYNEEDLIFTGATE_FORMAT_INCORRECT,//送货需要卡车升降台格式不正确，请重新输入
            'price' => PRICE_FORMAT_INCORRECT,//价格格式（一般为priceApiIdentify没有正确匹配）不正确，请重新输入
        ),
        100002 => array(
            'orderLTL' => ORDERLTL_CAN_NOT_MODIFY,//散板订单不能操作(订单状态不对)|403
        ),
        100004 => array(
            'staff' => USER_IDENTITY_AUTHENTICATION_FAILED,//后台用户不存在
            'member' => USER_IDENTITY_AUTHENTICATION_FAILED,//官网用户不存在
            'pickupWarehouse' => PICKUPWAREHOUSE_NOT_EXISTS,//取货仓库不存在|404
            'address' => ORDERLTL_ADDRESS_NOT_EXISTS,//取货地址不存在|404
            'deliveryAddress' => ORDERLTL_DELIVERYADDRESS_NOT_EXISTS,//送货地址不存在|404
            'priceApiRecord' => PRICEAPIIDENTIFY_NOT_EXISTS,//价格记录不存在|404
        ),
        100005 => RESOURCE_NOT_EXISTS,//主体不存在
        100400 => array(
            'orderLTL' => ORDERLTL_HAVE_BEEN_FROZEN,//散板订单被冻结|403
        ),
        100410 => array(
            'items' => ITEMS_EXCEEDS_THE_LIMIT,//货物数量超过限制, 应为`1-50`|403
        ),
        100411 => array(
            'pickup' => PICKUPNEEDLIFTGATE_PARAMETER_FORMAT_ERRORS,//是否需要尾板（升降台）在pickup的type=BUSINESS_DOCK, 必须为false|403
            'delivery' => DELIVERYNEEDLIFTGATE_PARAMETER_FORMAT_ERRORS,//是否需要尾板（升降台）在delivery的type=BUSINESS_DOCK, 必须为false|403
        ),
        100412 => array(
            'pickup' => PICKUPNEEDTRANSPORT_PARAMETER_FORMAT_ERRORS,//是否需要室内搬运在pickup的type=BUSINESS_DOCK, 必须为false|403
            'delivery' => DELIVERYNEEDTRANSPORT_PARAMETER_FORMAT_ERRORS,//是否需要室内搬运在delivery的type=BUSINESS_DOCK, 必须为false|403
        ),
        100413 => array(
            'name' => FILE_PARSING_FAILED,//文件解析失败|403
        ),
        100414 => array(
            'name' => THE_NUMBER_OF_PARSES_EXCEEDS_THE_LIMIT,//解析数量超过限制(目前限制为100条)|403
        ),
        100415 => array(
            'name' => FILE_PARSING_RETURNED_NULL,//文件解析返回空|403
        ),
        100421 => INTERFACE_QUOTATION_NOT_MATCHED,//未匹配到接口报价
    );
    
    const SCENARIOS = [
        'ORDERLTL_LIST'=>[
            'fields' => [],
            'include' => ''
        ],
        'ORDERLTL_FETCH_ONE'=>[
            'fields'=>[],
            'include'=>''
        ]
    ];

    public function __construct(string $baseurl = '', array $headers = [])
    {
        parent::__construct(
            new OrderLTLRestfulTranslator(),
            'orderLTL',
            $baseurl,
            $headers
        );
    }

    protected function getNullObject() : INull
    {
        return NullOrderLTL::getInstance();
    }

    protected function getAlonePossessMapErrors() : array
    {
        return self::MAP_ERROR;
    }

    public function scenario($scenario) : void
    {
        $this->scenario = isset(self::SCENARIOS[$scenario]) ? self::SCENARIOS[$scenario] : array();
    }

    public function insert(IOperateAble $operateAbleObject) : bool
    {
        $keys = $this->insertTranslatorKeys();
        $data = $this->getTranslator()->objectToArray($operateAbleObject, $keys);

        $this->post(
            'memberOrders/orderLTL',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($operateAbleObject);
            return true;
        }

        return false;
    }

    public function update(IOperateAble $operateAbleObject) : bool
    {
        $keys = $this->updateTranslatorKeys();
        $data = $this->getTranslator()->objectToArray($operateAbleObject, $keys);

        $this->patch(
            'memberOrders/orderLTL/'.$operateAbleObject->getMemberOrder()->getId(),
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($operateAbleObject);
            return true;
        }

        return false;
    }

    const OPERATION_KEYS = array(
        'bookingPickupDate',
        'pickupZipCode',
        'pickupAddressType',
        'deliveryZipCode',
        'deliveryAddressType',
        'pickupNeedTransport',
        'pickupNeedLiftgate',
        'deliveryNeedTransport',
        'deliveryNeedLiftgate',
        'poNumber',
        'items',
        'pickupVehicleType',
        'readyTime',
        'closeTime',
        'deliveryName',
        'deliveryReadyTime',
        'deliveryCloseTime',
        'weekendDelivery',
        'deliveryDescription',
        'remark',
        'pickupRequirement',
        'deliveryRequirement',
        'idfPickup',
        'priceApiRecordId',
        'priceApiIdentify',
        'address',
        'deliveryAddress',
        'pickupWarehouse',
        'member',
        'staff'
    );
    
    protected function insertTranslatorKeys() : array
    {
        return self::OPERATION_KEYS;
    }

    protected function updateTranslatorKeys() : array
    {
        return self::OPERATION_KEYS;
    }

    protected function enableTranslatorKeys() : array
    {
        return array();
    }

    protected function disableTranslatorKeys() : array
    {
        return array();
    }

    protected function deletedTranslatorKeys() : array
    {
        return array();
    }

    public function memberCancel(OrderLTL $orderLTL) : bool
    {
        $data = $this->getTranslator()->objectToArray($orderLTL, array('member'));
        unset($data['data']['attributes']);

        $this->patch(
            $this->getResource().'/'.$orderLTL->getId().'/cancel',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($orderLTL);
            return true;
        }

        return false;
    }

    public function staffCancel(OrderLTL $orderLTL) : bool
    {
        $data = $this->getTranslator()->objectToArray($orderLTL, array('staff'));
        unset($data['data']['attributes']);

        $this->patch(
            $this->getResource().'/'.$orderLTL->getId().'/cancel',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($orderLTL);
            return true;
        }

        return false;
    }

    public function confirm(OrderLTL $orderLTL) : bool
    {
        $data = $this->getTranslator()->objectToArray($orderLTL, array('staff'));
        unset($data['data']['attributes']);
       
        $this->patch(
            $this->getResource().'/'.$orderLTL->getId().'/confirm',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($orderLTL);
            return true;
        }

        return false;
    }

    public function batchConfirm(array $orderLTLList) : bool
    {
        foreach ($orderLTLList as $orderLTL) {
            $orderLTLData[] = array(
                'type' => 'orderLTL',
                'id' => strval($orderLTL->getId())
            );

            $data = $this->getTranslator()->objectToArray($orderLTL, array('staff'));
            unset($data['data']['attributes']);
        }

        $data['data']['relationships']['orderLTL']['data'] = $orderLTLData;

        $this->patch(
            $this->getResource().'/batchConfirm',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObjects();
            return true;
        }

        return false;
    }

    public function registerPosition(OrderLTL $orderLTL) : bool
    {
        $data = $this->getTranslator()->objectToArray(
            $orderLTL,
            array('position', 'stockInNumber', 'stockInTime', 'staff')
        );
     
        $this->patch(
            $this->getResource().'/'.$orderLTL->getId().'/register/position',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($orderLTL);
            return true;
        }

        return false;
    }

    public function freeze(OrderLTL $orderLTL) : bool
    {
        $data = $this->getTranslator()->objectToArray($orderLTL, array('staff'));
        unset($data['data']['attributes']);
       
        $this->patch(
            $this->getResource().'/'.$orderLTL->getId().'/freeze',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($orderLTL);
            return true;
        }

        return false;
    }

    public function unFreeze(OrderLTL $orderLTL) : bool
    {
        $data = $this->getTranslator()->objectToArray($orderLTL, array('staff'));
        unset($data['data']['attributes']);
       
        $this->patch(
            $this->getResource().'/'.$orderLTL->getId().'/unFreeze',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->translateToObject($orderLTL);
            return true;
        }

        return false;
    }

    protected function getNullParseTask() : INull
    {
        return NullParseTask::getInstance();
    }

    protected function getParseTaskRestfulTranslator() : ParseTaskRestfulTranslator
    {
        return new ParseTaskRestfulTranslator();
    }

    public function parse(ParseTask $parseTask) : bool
    {
        $data = $this->getParseTaskRestfulTranslator()->objectToArray($parseTask, array('fileName'));

        $this->post(
            $this->getResource().'/parse',
            $data
        );
        
        if ($this->isSuccess()) {
            $this->getParseTaskRestfulTranslator()->arrayToObject($this->getContents(), $parseTask);
            return true;
        }

        return false;
    }

    protected function getNullOrderPriceReport() : INull
    {
        return NullOrderPriceReport::getInstance();
    }

    protected function getOrderPriceReportRestfulTranslator() : OrderPriceReportRestfulTranslator
    {
        return new OrderPriceReportRestfulTranslator();
    }

    public function calculate(OrderLTL $orderLTL) : array
    {
        $keys = array(
            'bookingPickupDate',
            'pickupZipCode',
            'pickupAddressType',
            'deliveryZipCode',
            'deliveryAddressType',
            'pickupNeedTransport',
            'pickupNeedLiftgate',
            'deliveryNeedTransport',
            'deliveryNeedLiftgate',
            'items',
            'pickupVehicleType',
            'pickupRequirement',
            'deliveryRequirement',
            'member',
            'staff'
        );
        $data = $this->getTranslator()->objectToArray($orderLTL, $keys);
        
        $this->post(
            'memberOrders/orderLTL/calculate',
            $data
        );

        if ($this->isSuccess()) {
            return $this->getOrderPriceReportRestfulTranslator()->arrayToObjects($this->getContents());
        }

        return array(0, array());
    }

    public function fetchOneCalculateRecord($id)
    {
        $this->get('calculateRecords/'.$id);

        if ($this->isSuccess()) {
            return $this->getOrderPriceReportRestfulTranslator()->arrayToObject($this->getContents());
        }

        return $this->getNullOrderPriceReport();
    }

    protected function getItemLTLRestfulTranslator() : ItemLTLRestfulTranslator
    {
        return new ItemLTLRestfulTranslator();
    }

    public function calculateGoodsLevel(ItemLTL $itemLTL) : bool
    {
        $data = $this->getItemLTLRestfulTranslator()->objectToArray(
            $itemLTL,
            array('length', 'width', 'height', 'weight', 'weightUnit')
        );

        $this->post(
            'orderLTL/calculateGoodsLevel',
            $data
        );

        if ($this->isSuccess()) {
            $this->getItemLTLRestfulTranslator()->arrayToObject($this->getContents(), $itemLTL);
            return true;
        }

        return false;
    }
}
